Removing an old, cherished, yet pointless caveat "This documentation is
[supercollider.git] / Help / Streams-Patterns-Events / A Practical Guide / PG_Cookbook02_Manipulating_Patterns.html
blob5fd4b104bb5626d78018f2698b7c9ddb12f40786
1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2 <html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <meta http-equiv="Content-Style-Type" content="text/css">
6 <title></title>
7 <meta name="Generator" content="Cocoa HTML Writer">
8 <meta name="CocoaVersion" content="949.43">
9 <style type="text/css">
10 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Helvetica}
11 p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
12 p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica}
13 p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
14 p.p5 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
15 p.p6 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; min-height: 12.0px}
16 p.p7 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #ae1a19}
17 p.p8 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #2b7000}
18 p.p9 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; color: #001bec}
19 span.s1 {color: #0016bd}
20 span.s2 {color: #2b7000}
21 span.s3 {color: #000000}
22 span.s4 {color: #606060}
23 span.s5 {font: 12.0px Helvetica}
24 span.Apple-tab-span {white-space:pre}
25 </style>
26 </head>
27 <body>
28 <p class="p1"><b>Manipulating pattern data</b></p>
29 <p class="p2"><br></p>
30 <p class="p3"><b>Merging (interleaving) independent streams</b></p>
31 <p class="p2"><br></p>
32 <p class="p4">Suppose you wanted a pattern that generated pitches in a lower range 70% of the time, and a higher range the other 30%. For purely random patterns, this is simple because the pattern for each range has no memory (the next value does not depend on the previous value in any perceptible way). The random number generator patterns (<a href="../Patterns/Pwhite.html"><span class="s1">Pwhite</span></a>) return one element before yielding control back to the "selector" (<a href="../Patterns/Pwrand.html"><span class="s1">Pwrand</span></a>).</p>
33 <p class="p2"><br></p>
34 <p class="p5"><span class="Apple-tab-span"> </span><span class="s2">\degree</span>, <span class="s1">Pwrand</span>([<span class="s1">Pwhite</span>(-7, 11, 1), <span class="s1">Pwhite</span>(7, 18, 1)], #[0.7, 0.3], <span class="s1">inf</span>)</p>
35 <p class="p2"><br></p>
36 <p class="p4">This does not work if the ranges need to keep their own integrity. For that, Pnsym1 is ideal. We create a dictionary with named patterns, each of which maintain their own streams. Then we choose randomly between their names, picking one value from whichever stream is chosen this cycle.</p>
37 <p class="p2"><br></p>
38 <p class="p4">This use of <a href="../Patterns/Pseries.html"><span class="s1">Pseries</span></a> is essentially a random walk among scale degrees. It has more linear continuity than the equal distribution generated by Pwhite. Even though the higher range interrupts from time to time, the continuity should still be audible.</p>
39 <p class="p2"><br></p>
40 <p class="p5">(</p>
41 <p class="p5"><span class="s1">var</span><span class="Apple-tab-span"> </span>melodies = (</p>
42 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>lowMelody: <span class="s1">Pseries</span>(4, <span class="s1">Prand</span>(#[-2, -1, 1, 2], <span class="s1">inf</span>), <span class="s1">inf</span>).fold(-7, 11),</p>
43 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>highMelody: <span class="s1">Pseries</span>(14, <span class="s1">Prand</span>(#[-3, -2, 2, 3], <span class="s1">inf</span>), <span class="s1">inf</span>).fold(7, 18)</p>
44 <p class="p5"><span class="Apple-tab-span"> </span>);</p>
45 <p class="p6"><br></p>
46 <p class="p5">p = <span class="s1">Pbind</span>(</p>
47 <p class="p5"><span class="Apple-tab-span"> </span><span class="s2">\degree</span>, <span class="s1">Pnsym1</span>(<span class="s1">Pwrand</span>(#[lowMelody, highMelody], [0.7, 0.3], <span class="s1">inf</span>), melodies),</p>
48 <p class="p5"><span class="Apple-tab-span"> </span><span class="s2">\dur</span>, <span class="s1">Pwrand</span>(#[0.25, 0.5], #[0.4, 0.6], <span class="s1">inf</span>)</p>
49 <p class="p5">).play;</p>
50 <p class="p5">)</p>
51 <p class="p6"><br></p>
52 <p class="p5">p.stop;</p>
53 <p class="p2"><br></p>
54 <p class="p2"><br></p>
55 <p class="p3"><b>Reading an array forward or backward arbitrarily</b></p>
56 <p class="p2"><br></p>
57 <p class="p4">Here's an interesting one. We have an array of possible output values, and we want the pattern to move forward or backward through the array depending on some kind of user input.</p>
58 <p class="p2"><br></p>
59 <p class="p4">There is actually a pattern that handles this already, based on the standard programming concept of a (random) walk. In a random walk, there is an "observer" who is at a position within an array. The observer moves randomly by some number of steps forward or backward. In the SuperCollider pattern implementation, <a href="../Patterns/Pwalk.html"><span class="s1">Pwalk</span></a>, the steps don't have to be random. So here, we determine the step size from a slider.</p>
60 <p class="p2"><br></p>
61 <p class="p4">In general, GUI objects should not be used for data storage. The approach here is to save the step size into a variable, and then refer to that variable in the Pwalk pattern.</p>
62 <p class="p2"><br></p>
63 <p class="p5">(</p>
64 <p class="p7"><span class="s1">var</span><span class="s3"><span class="Apple-tab-span"> </span>pitches = (0..14),<span class="Apple-tab-span"> </span></span>// replace with other pitches you want</p>
65 <p class="p5"><span class="Apple-tab-span"> </span>move = 0,</p>
66 <p class="p5"><span class="Apple-tab-span"> </span>window, slider;</p>
67 <p class="p6"><br></p>
68 <p class="p5">window = <span class="s1">Window</span>.new(<span class="s4">"Mouse Transport"</span>, <span class="s1">Rect</span>(5, 100, 500, 50));</p>
69 <p class="p5">slider = <span class="s1">Slider</span>.new(window, <span class="s1">Rect</span>(5, 5, 490, 20))</p>
70 <p class="p5"><span class="Apple-tab-span"> </span>.action_({ <span class="s1">|view|</span></p>
71 <p class="p5"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span>move = (view.value * 4 - 2).round;</p>
72 <p class="p5"><span class="Apple-tab-span"> </span>})</p>
73 <p class="p5"><span class="Apple-tab-span"> </span>.value_(0.5);</p>
74 <p class="p5">window.front;</p>
75 <p class="p6"><br></p>
76 <p class="p5">p = <span class="s1">Pbind</span>(</p>
77 <p class="p7"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>// Pfunc is the direction to move through the array</p>
78 <p class="p7"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>// it could be anything</p>
79 <p class="p7"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>// <span class="Apple-converted-space">  </span>- could read from MIDI or HID and convert it into a step</p>
80 <p class="p7"><span class="s3"><span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span></span>// <span class="Apple-converted-space">  </span>- could be a GUI control, as it is here</p>
81 <p class="p5"><span class="Apple-tab-span"> </span><span class="s2">\degree</span>, <span class="s1">Pwalk</span>(pitches, <span class="s1">Pfunc</span> { move }, 1, 7),</p>
82 <p class="p5"><span class="Apple-tab-span"> </span><span class="s2">\dur</span>, 0.25</p>
83 <p class="p5">).play;</p>
84 <p class="p5">)</p>
85 <p class="p6"><br></p>
86 <p class="p5">p.stop;</p>
87 <p class="p2"><br></p>
88 <p class="p4"><b>Third-party extension alert:</b> The <a href="../Patterns/Pwalk.html"><span class="s1">Pwalk</span></a> pattern shown here moves forward and backward in a preset array. To do the same thing with the results of a pattern, see <b>Pscratch</b> in the ddwPatterns quark. An especially fun use of Pscratch is to use it on an event pattern like Pbind, skipping around in a series of fully realized note events.</p>
89 <p class="p2"><br></p>
90 <p class="p2"><br></p>
91 <p class="p3"><b>Changing Pbind value patterns on the fly</b></p>
92 <p class="p2"><br></p>
93 <p class="p4">Patterns are converted into streams to generate values (or events). By design, there is no way to access the internal state of the stream. This means, for Pbind and similar patterns, the streams producing values for the event keys are invisible. So, it isn't possible to reach inside the stream and change them while the pattern is playing.</p>
94 <p class="p2"><br></p>
95 <p class="p4">What we can do instead is base the Pbind on <b>pattern proxies</b> -- objects that take the place of a pattern. The <a href="../../Libraries/JITLib/Patterns/PatternProxy.html"><span class="s1">PatternProxy</span></a> is a single object that creates a single stream within Pbind, but it looks for its values to the pattern and stream contained inside the proxy. Changing the proxy's pattern replaces the stream, without having to touch the Pbind's closed box.</p>
96 <p class="p2"><br></p>
97 <p class="p4">In the first example, pattern proxies are held in environment variables, and they can be manipulated through those variables.</p>
98 <p class="p2"><br></p>
99 <p class="p5">(</p>
100 <p class="p5">~degree = <span class="s1">PatternProxy</span>(<span class="s1">Pn</span>(<span class="s1">Pseries</span>(0, 1, 8), <span class="s1">inf</span>));</p>
101 <p class="p5">~dur = <span class="s1">PatternProxy</span>(<span class="s1">Pn</span>(0.25, <span class="s1">inf</span>));</p>
102 <p class="p6"><br></p>
103 <p class="p5">p = <span class="s1">Pbind</span>(</p>
104 <p class="p5"><span class="Apple-tab-span"> </span><span class="s2">\degree</span>, ~degree,</p>
105 <p class="p5"><span class="Apple-tab-span"> </span><span class="s2">\dur</span>, ~dur</p>
106 <p class="p5">).play;</p>
107 <p class="p5">)</p>
108 <p class="p6"><br></p>
109 <p class="p5">~degree.source = (<span class="s1">Pexprand</span>(1, 8, <span class="s1">inf</span>) - 1).round;</p>
110 <p class="p6"><br></p>
111 <p class="p5">~dur.source = <span class="s1">Pwrand</span>(#[0.25, 0.5, 0.75], #[0.5, 0.3, 0.2], <span class="s1">inf</span>);</p>
112 <p class="p6"><br></p>
113 <p class="p5">p.stop;</p>
114 <p class="p2"><br></p>
115 <p class="p2"><br></p>
116 <p class="p4">Another way is to use <a href="../../Libraries/JITLib/Patterns/Pdefn.html"><span class="s1">Pdefn</span></a>, which is a global namespace of proxies for value patterns. (Because of the different requirements for handling values and event patterns, there are two namespaces: <a href="../../Libraries/JITLib/Patterns/Pdef.html"><span class="s1">Pdef</span></a> for event patterns like Pbind, and Pdefn for value patterns such as \degree and \dur here.) Storage is all taken care of for you, no need for variables of your own.</p>
117 <p class="p2"><br></p>
118 <p class="p5">(</p>
119 <p class="p5"><span class="s1">Pdefn</span>(<span class="s2">\degree</span>, <span class="s1">Pn</span>(<span class="s1">Pseries</span>(0, 1, 8), <span class="s1">inf</span>));</p>
120 <p class="p5"><span class="s1">Pdefn</span>(<span class="s2">\dur</span>, <span class="s1">Pn</span>(0.25, <span class="s1">inf</span>));</p>
121 <p class="p6"><br></p>
122 <p class="p5">p = <span class="s1">Pbind</span>(</p>
123 <p class="p8"><span class="s3"><span class="Apple-tab-span"> </span></span>\degree<span class="s3">, </span><span class="s1">Pdefn</span><span class="s3">(</span>\degree<span class="s3">),</span></p>
124 <p class="p8"><span class="s3"><span class="Apple-tab-span"> </span></span>\dur<span class="s3">, </span><span class="s1">Pdefn</span><span class="s3">(</span>\dur<span class="s3">)</span></p>
125 <p class="p5">).play;</p>
126 <p class="p5">)</p>
127 <p class="p6"><br></p>
128 <p class="p5"><span class="s1">Pdefn</span>(<span class="s2">\degree</span>, (<span class="s1">Pexprand</span>(1, 8, <span class="s1">inf</span>) - 1).round);</p>
129 <p class="p6"><br></p>
130 <p class="p5"><span class="s1">Pdefn</span>(<span class="s2">\dur</span>, <span class="s1">Pwrand</span>(#[0.25, 0.5, 0.75], #[0.5, 0.3, 0.2], <span class="s1">inf</span>));</p>
131 <p class="p6"><br></p>
132 <p class="p5">p.stop;</p>
133 <p class="p2"><br></p>
134 <p class="p4"><b>Third-party extension alert:</b> The ddwChucklib quark defines a third way of doing this, using object prototyping (based on Environments) to create objects that encapsulate all the information needed to perform a musical behavior. Patterns stored in the prototype's variables are automatically available as pattern proxies to the object's pattern, making it easier to create complex, malleable "processes" which can be replicated as separate objects that don't interfere with each other. It's a step toward object-oriented modeling of musical behaviors without requiring hardcoded classes that are specific to one piece or another.</p>
135 <p class="p2"><br></p>
136 <p class="p2"><br></p>
137 <p class="p9"><span class="s3">Previous:<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><a href="PG_Cookbook01_Basic_Sequencing.html"><span class="s5">PG_Cookbook01_Basic_Sequencing</span></a></span></p>
138 <p class="p9"><span class="s3">Next:<span class="Apple-tab-span"> </span><span class="Apple-tab-span"> </span><a href="PG_Cookbook03_External_Control.html"><span class="s5">PG_Cookbook03_External_Control</span></a></span></p>
139 </body>
140 </html>